﻿<ComClass(ClsPoint3d.ClassId, ClsPoint3d.InterfaceId, ClsPoint3d.EventsId)>
Public Class ClsPoint3d

#Region "COM GUID"
    ' 这些 GUID 提供此类的 COM 标识 
    ' 及其 COM 接口。若更改它们，则现有的
    ' 客户端将不再能访问此类。
    Public Const ClassId As String = "c8036626-f61f-4c9b-a19b-945d8611a314"
    Public Const InterfaceId As String = "0691fa4f-6b8b-40fa-a666-3c304beb2593"
    Public Const EventsId As String = "e947cc03-840f-4807-9c00-12cd9b480ced"
#End Region

    ' 可创建的 COM 类必须具有一个不带参数的 Public Sub New() 
    ' 否则， 将不会在 
    ' COM 注册表中注册此类，且无法通过
    ' CreateObject 创建此类。
    Public Sub New()
        MyBase.New()
    End Sub

#Region "字段和属性"
    Private _xValue As Double
    Private _yValue As Double
    Private _zValue As Double
    Public ReadOnly Property Origin As ClsPoint3d
        Get
            Return New ClsPoint3d() With {.X = 0, .Y = 0, .Z = 0}
        End Get
    End Property
    Public Property X As Double
        Get
            Return _xValue
        End Get
        Set(value As Double)
            _xValue = value
        End Set
    End Property
    ''' <summary>
    ''' 纵坐标
    ''' </summary>
    ''' <returns></returns>
    Public Property Y As Double
        Get
            Return _yValue
        End Get
        Set(value As Double)
            _yValue = value
        End Set
    End Property
    Public Property Z As Double
        Get
            Return _zValue
        End Get
        Set(ByVal value As Double)
            _zValue = value
        End Set
    End Property


    ''' <summary>
    ''' 转字符串格式
    ''' </summary>
    ''' <returns></returns>
    Public ReadOnly Property StringStyle As String
        Get
            Return $"({Me.X},{Me.Y},{Me.Z})"
        End Get
    End Property
#End Region

#Region "构造函数,初始化"

    ''' <summary>
    ''' 构造函数
    ''' </summary>
    ''' <param name="x1">传入的横坐标</param>
    ''' <param name="y1">传入的纵坐标</param>
    ''' <param name="z1">传入的Z坐标</param>
    Public Sub CreatorByXyz(x1 As Double, y1 As Double, z1 As Double)
        Me.X = x1
        Me.Y = y1
        Me.Z = z1
    End Sub

    ''' <summary>
    ''' 构造函数
    ''' </summary>
    ''' <param name="arr">2个元素的double</param>
    Public Sub CreatorByArray(arr() As Double)
        Me.X = arr(LBound(arr))
        Me.Y = arr(LBound(arr) + 1)
        Me.Z = arr(UBound(arr))
    End Sub

    ''' <summary>
    ''' 构造函数
    ''' </summary>
    ''' <param name="arr">2个元素的double</param>
    Public Sub CreatorByVariant(arr As Object)
        Me.X = arr(LBound(arr))
        Me.Y = arr(LBound(arr) + 1)
        Me.Z = arr(UBound(arr))
    End Sub

    ''' <summary>
    ''' (x,y) 格式的字符串转点对象
    ''' </summary>
    ''' <param name="listPt">(x,y) 格式的字符串</param>
    ''' <param name="split">x与y之间的分割符.默认未逗号</param>
    Public Sub CreatorByString(listPt As String, Optional split As String = ",")
        Dim ptwithspliter = listPt.Trim().Substring(1, listPt.Trim().Length - 2)
        Dim arr = ptwithspliter.Split({split}, StringSplitOptions.RemoveEmptyEntries)
        Me.X = arr(LBound(arr))
        Me.Y = arr(LBound(arr) + 1)
        Me.Z = arr(UBound(arr))
    End Sub

#End Region

#Region "操作"
    Public Function Add(ByVal vAdd As ClsVector3d) As ClsPoint3d
        Return New ClsPoint3d With {
        .X = (Me.X + vAdd.X),
        .Y = (Me.Y + vAdd.Y),
        .Z = (Me.Z + vAdd.Z)
    }
    End Function
    Public Function Subtract(ByVal vSubtract As ClsVector3d) As ClsPoint3d
        Return New ClsPoint3d With {
        .X = (Me.X - vSubtract.X),
        .Y = (Me.Y - vSubtract.Y),
        .Z = (Me.Z - vSubtract.Z)
    }
    End Function



#End Region

#Region "转换"
    Public Function GetVector3dTo(ByVal ep As ClsPoint3d) As ClsVector3d
        Return New ClsVector3d With {
            .X = (ep.X - Me.X),
            .Y = (ep.Y - Me.Y),
            .Z = (ep.Z - Me.Z)
        }
    End Function

    Public Function GetAsVector3d() As ClsVector3d
        Return Me.Origin.GetVector3dTo(Me)
    End Function
    Public Function ToArray() As Double()
        Return {Me.X, Me.Y, Me.Z}
    End Function

#End Region

#Region "运算"

    Public Function GetDistanceTo(ByVal ep As ClsPoint3d) As Double
        Dim deltaX = Me.X - ep.X
        Dim deltaY = Me.Y - ep.Y
        Dim deltaZ = Me.Z - ep.Z
        Return Math.Sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ)
    End Function

    Public Function IsEqualTo(ByVal b As ClsPoint3d) As Boolean
        Dim m As New ClsMath
        Return m.IsEqual(Me.X, b.X) AndAlso m.IsEqual(Me.Y, b.Y) AndAlso m.IsEqual(Me.Z, b.Z)
    End Function

    ''' <summary>
    ''' 求当前点与给定点的中点
    ''' </summary>
    ''' <param name="ep">给定点</param>
    ''' <returns>中点</returns>
    Public Function GetMidPointTo(ByVal ep As ClsPoint3d) As ClsPoint3d
        Return New ClsPoint3d With {
        .X = (Me.X + ep.X) * 0.5,
        .Y = (Me.Y + ep.Y) * 0.5,
        .Z = (Me.Z + ep.Z) * 0.5
    }
    End Function


    ''' <summary>
    ''' 当前点在直线上的投影
    ''' </summary>
    ''' <param name="sp">直线的起点</param>
    ''' <param name="ep">直线的终点</param>
    ''' <returns>当前点在直线上的投影点的坐标</returns>
    Public Function GetProjectionPointToLine(sp As ClsPoint3d, ep As ClsPoint3d) As ClsPoint3d
        Dim vspep = sp.GetVector3dTo(ep)
        Dim vspme = sp.GetVector3dTo(Me)
        Dim x = vspme.ProjectionOnVector(vspep).Length '当前点在给定直线上的投影长度
        Return sp.Add(vspep.UnitVector.Multiply(x)) '当前点在给定直线上的投影点坐标
    End Function

    ''' <summary>
    ''' 判断点时候在平面内
    ''' </summary>
    ''' <param name="plane"></param>
    ''' <returns></returns>
    Public Function IsOnPlane(plane As ClsPlane) As Boolean
        Dim v As ClsVector3d = plane.Original.GetVector3dTo(Me)
        Dim mathHelper As New ClsMath
        If mathHelper.IsZero(v.Z) Then
            Return True
        Else
            Return False
        End If
    End Function

    ''' <summary>
    ''' 点在平面的正投影点
    ''' </summary>
    ''' <param name="plane"></param>
    ''' <returns>点在平面的正投影点</returns>
    Public Function OrthoProjectPoint(plane As ClsPlane) As ClsPoint3d
        Dim va0 As ClsVector3d = Me.GetVector3dTo(plane.Original)
        Dim planarNeg As ClsVector3d = plane.Normal.NegateVector
        Return Me.Add(va0.ProjectionOnVector(planarNeg))
    End Function

    ''' <summary>
    ''' 点的矩阵变换结果的计算
    ''' </summary>
    ''' <param name="mtArr">由类clsmatrix4ex创建的矩阵</param>
    ''' <returns></returns>
    Public Function TransformBy(mtArr(,) As Double) As ClsPoint3d
        Debug.Assert(mtArr.GetLength(0) = 4 And mtArr.GetLength(1) = 4, "参数必须是4x4的数组")
        Dim mt As New Matrix4(mtArr)
        Return mt * Me
    End Function


#End Region

#Region "非com可见"
    Public Overrides Function ToString() As String
        Return $"X={Me.X},Y={Me.Y},Z={Me.Z}"
    End Function
#End Region

#Region "与cad转化"

    Public Function CreateFromAcadObject(obj As Object) As Boolean
        If TypeName(obj) <> "IAcadPoint" Then
            Return False
        Else
            Call CreatorByArray(obj.Coordinates)
            Return True
        End If
    End Function
#End Region

End Class


